/*
 * To change this template, choose Tools | Templates and open the template in
 * the editor.
 */

package mundo;
/**
 * Class that creates a Map Object for playing the game. It can build a Map from
 * an array of a defined set of integers, or from a string.
 * 
 * @author JuanFer
 */
public class Map
{

    /**
     * It is a matrix of places that represents the map. We would expect each
     * place to have the same size.
     */
    public MapPiece place[][];
    
    public int[][] pieces;

    /**
     * Constructor that receives a matrix of a well defined set of integers.
     * 
     * @param pieces
     */
    public Map(int p[][])
    {
//    	System.out.println("entro");
    	pieces = p;
//    	System.out.println("entro");
	    setPlace(pieces);
//    	System.out.println("dir"+this.hashCode());
    }

    /**
     * Constructor that creates Map from a matrix of MapPieces.
     * 
     * @param newPlace
     */
    public Map(MapPiece[][] newPlace)
    {
    	place = newPlace;
    }

    /**
     * Constructor that creates a Map from a message string.
     * 
     * @param cadena
     * @throws UnmapableException
     */
    public Map(String cadena) throws UnmapableException
    {
	pieces = createMapMatrixFromString(cadena);
	setPlace(pieces);
    }

    /**
     * Checks if one line of the string entered begins and ends with a wall.
     * Precondition: String is parsed into one line strings with no enter.
     * 
     * @param cadena
     * @return true if string begins and ends with wall
     */
    public boolean beginsEndsWithWall(String cadena)
    {
	return (cadena.charAt(0) == 'b' || cadena.charAt(0) == 'B')
		&& (cadena.charAt(cadena.length() - 1) == 'b' || cadena
			.charAt(cadena.length() - 1) == 'B');
    }

    /**
     * Gets the character associated with an entry of the matrix.
     * 
     * @param i
     * @return character
     */
    public char charInverseTranslate(int i)
    {
	if (i == 0)
	{
	    return 'B';
	}
	if (i == 1)
	{
	    return 'L';
	}
	if (i == 2)
	{
	    return 'W';
	}
	if (i == 3)
	{
	    return 'G';

	}
	if (i == 4)
	{
	    return 'O';
	}
	if (i == 5)
	{
	    return 'P';
	}
	if (i == 6)
	{
	    return 'A';
	}
	return 'e';
    }

    /**
     * Function that translates the string caracter to the integer elements of
     * the integer matrix for creating a place.
     * 
     * @param c
     * @return integer that represents MapPiece type.
     */
    public int charTranslate(char c)
    {
	if (c == 'B' || c == 'b')
	{
	    return 0;
	}
	if (c == 'W' || c == 'w')
	{
	    return 2;
	}
	if (c == 'G' || c == 'g')
	{
	    return 3;
	}
	if (c == 'L' || c == 'l')
	{
	    return 1;
	}
	if (c == 'O' || c == 'o')
	{
	    return 4;
	}
	if (c == 'P' || c == 'p')
	{
	    return 5;
	}
	if (c == 'A' || c == 'a')
	{
	    return 6;
	}
	return -1;
    }

    /**
     * Creates the matrix of integers for use in the constructur.
     * 
     * @param cadenas
     * @return Integer matrix that represents map
     * @throws UnmapableException
     */
    public int[][] createMapMatrix(String[] cadenas) throws UnmapableException
    {
	// tirar exception llamada unable to create map exception.
	boolean test = hasSameSize(cadenas);
	if (!test)
	{
	    throw new UnmapableException(
		    "Mapa no tiene las dimensiones correctas.");
	}
	for (int i = 0; i < cadenas.length; i++)
	{
	    if (!isWellDefined(cadenas[i]))
	    {
		throw new UnmapableException(
			"Mapa no tiene los caracteres correctos.");
	    }
	}
//	if (!isWall(cadenas[0]))
//	{
//	    throw new UnmapableException(
//		    "Mapa no tiene sus limites bien definidos1.");
//	}
//	if (!isWall(cadenas[cadenas.length - 1]))
//	{
//	    throw new UnmapableException(
//		    "Mapa no tiene sus limites bien definidos2.");
//	}
//	for (int i = 1; i < cadenas.length - 2; i++)
//	{
//	    if (!beginsEndsWithWall(cadenas[i]))
//	    {
//		throw new UnmapableException(
//			"Mapa no tiene sus limites bien definidos3.");
//	    }
//	}
	int[][] thisMap = new int[cadenas[0].length()][cadenas.length];
	for (int i = 0; i < cadenas[0].length(); i++)
	{
	    for (int j = 0; j < cadenas.length; j++)
	    {
		thisMap[i][j] = charTranslate(cadenas[j].charAt(i));
	    }
	}
	return thisMap;
    }

    /**
     * Creates the matrix of integres from the original string with enters.
     * 
     * @param cadena
     * @return Creates matrix from string
     * @throws UnmapableException
     */
    public int[][] createMapMatrixFromString(String cadena)
	    throws UnmapableException
    {
	String[] cadenas = createStringChain(cadena);
	return createMapMatrix(cadenas);
    }

    /**
     * Separates by enters each line in the string into an array of strings.
     * 
     * @param cadena
     * @return String array.
     */
    public String[] createStringChain(String cadena)
    {
	String[] cadenas;
//	int enterCount = 0;
//	int lastEnter = 0;
//	int count = 0;
//	for (int i = 0; i < cadena.length(); i++)
//	{
//	    if (cadena.charAt(i) == '\n')
//	    {
//		enterCount++;
//	    }
//	}
	
//
//	for (int i = 0; i < cadena.length(); i++)
//	{
//	    if (cadena.charAt(i) == '\n')
//	    {
//		cadenas[count] = cadena.substring(lastEnter, i);
//		lastEnter = i + 1;
//		count++;
//	    }
//	}
//	cadenas[enterCount] = cadena.substring(lastEnter);
    int i = 0;
	StringTokenizer tk = new StringTokenizer(cadena,"\n");
	int tamano = tk.countTokens();
	cadenas = new String[tamano];
    while (tk.hasMoreTokens()) {
    	cadenas[i]=tk.nextToken();
    	i++;
    }
	return cadenas;
    }

    /**
     * Checks if each string in the array has the same size.
     * 
     * @param cadenas
     * @return true if they have same size.
     */
    public boolean hasSameSize(String[] cadenas)
    {
	boolean test = true;
	int size = cadenas[0].length();
	for (int i = 1; i < cadenas.length; i++)
	{
	    test = test && (cadenas[i].length() == size);
	}
	return test;
    }

    /**
     * Says if the MapPiece place toward which the robot sees is walkable.
     * 
     * @param x
     * @param y
     * @return true if it is walkable
     */
    protected boolean isWalkable(int x, int y)
    {
	return place[x][y].walkable();
    }

    /**
     * Checks if the string evaluated is a wall.
     * 
     * @param cadena
     * @return ture if it is wall
     */
    public boolean isWall(String cadena)
    {
	boolean test = true;
	for (int i = 0; i < cadena.length(); i++)
	{
	    test = test && (cadena.charAt(i) == 'b' || cadena.charAt(i) == 'B');
	}
	return test;
    }

    /**
     * Function that checks if the string uses expected characters.
     * 
     * @param cadena
     * @return true if it is well defined
     */
    protected boolean isWellDefined(String cadena)
    {
	boolean test = true;
	boolean testj = true;
	String validos = "BbWwGgLlOoPpAa";
	for (int i = 0; i < cadena.length(); i++)
	{
	    testj = false;
	    for (int j = 0; j < validos.length(); j++)
	    {
		if (cadena.charAt(i) == validos.charAt(j))
		{
		    testj = true;
		}
	    }
	    test = test & testj;
	}
	return test;
    }

    /**
     * Returns a map object given a string with enters.
     * 
     * @param cadena
     * @return Map object given a string
     * @throws UnmapableException
     */
    protected Map MapCreator(String cadena) throws UnmapableException
    {
	return new Map(createMapMatrixFromString(cadena));
    }

    /**
     * Regenerates message form the integer matrix.
     * 
     * @return
     */
    protected String messageRegeneration()
    {
	int[][] intMatrix = recreateIntegerMatrix();
	String message = "";
	for (int j = 0; j < intMatrix[0].length; j++)
	{
	    for (int i = 0; i < intMatrix.length; i++)
	    {
		message = message + charInverseTranslate(intMatrix[i][j]);
	    }
	    message = message + "\n";
	}
	return message;
    }

    /**
     * Regenerates integer matrix from the places atribute
     * 
     * @return Matrix of integers
     */
    public int[][] recreateIntegerMatrix()
    {
	int[][] intMatrix = new int[place.length][place[0].length];
	for (int i = 0; i < place.length; i++)
	{
	    for (int j = 0; j < place[0].length; j++)
	    {
		if (place[i][j].isHasObj())
		{
		    intMatrix[i][j] = 4;
		} else if (place[i][j].isPainted())
		{
		    intMatrix[i][j] = 5;
		} else if (place[i][j].isPainted() && place[i][j].isHasObj())
		{
		    intMatrix[i][j] = 6;
		} else
		{
		    intMatrix[i][j] = place[i][j].getGroundType();
		}

	    }
	}
	return intMatrix;
    }

    /**
     * Sets place.
     * 
     * @param pieces
     */
    public void setPlace(int pieces[][])
    {
	place = new MapPiece[pieces.length][pieces[0].length];
//	System.out.println("entro");

	for (int i = 0; i < pieces.length; i++)
	{
	    for (int j = 0; j < pieces[0].length; j++)
	    {
		place[i][j] = new MapPiece(pieces[i][j]);
//    	System.out.println("entro");
	    }
	}
    }

    /**
     * Sets the MapPiece place to the specified type.
     * 
     * @param x
     * @param y
     * @param type
     */
    public void setPlacexy(int x, int y, int type)
    {
	place[x][y] = new MapPiece(type);
    }
    
    public MapPiece[][] getMapPiece(){
    	return place;
    }
    
    public int[][] getPieces(){
    	return pieces;
    }
   

}
